package com.ccrfid.rmc6.service.video;

import com.ccrfid.rmc6.entity.video.VideoPlatformEntity;
import com.ccrfid.rmc6.pojo.hikartemis.ArtemisPath;
import com.ccrfid.rmc6.pojo.hikartemis.req.*;
import com.ccrfid.rmc6.pojo.hikartemis.resp.*;
import com.ccrfid.rmc6.repository.video.VideoPlatformRepository;
import com.ccrfid.rmc6.util.JsonUtil;
import com.hikvision.artemis.sdk.ArtemisHttpUtil;
import com.hikvision.artemis.sdk.config.ArtemisConfig;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.transaction.Transactional;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Transactional
public class HikArtemisServiceImpl implements HikArtemisService {
    private static final Logger logger = LoggerFactory.getLogger(HikArtemisServiceImpl.class);
    private static final String contentType = "application/json;charset=UTF-8";
    private static final int defaultPageSize = 100;

    @Autowired
    private VideoPlatformRepository videoPlatformRepository;

    private String initArtemisConfig() {
        List<VideoPlatformEntity> list = getArtemisPlatform();
        if (list != null && list.size() > 0) {
            VideoPlatformEntity platformEntity = list.get(0);
            ArtemisConfig.appKey = platformEntity.getUsername();
            ArtemisConfig.appSecret = platformEntity.getPasswd();

            String serviceUrl = platformEntity.getSyncServiceUrl();
            int index = serviceUrl.indexOf("//");
            if (index > 0 && index < 7) {
                ArtemisConfig.host = serviceUrl.substring(index + 2);
                return serviceUrl.substring(0, index + 2);
            } else {
                ArtemisConfig.host = platformEntity.getIp() + ":" + platformEntity.getPort();
                return "https://";
            }
        } else {
            logger.error("Hikvision Infovision SPCC info not found!");
            return null;
        }
    }

    private List<VideoPlatformEntity> getArtemisPlatform() {
        List<VideoPlatformEntity> list = videoPlatformRepository.getAllByPlatformVersion(521);
        if (list != null && list.size() > 0) {
            return list;
        } else {
            return videoPlatformRepository.getAllByPlatformVersion(522);
        }
    }

    @Override
    public boolean isHikArtemisType(Integer type) {
        return type != null && (type.equals(521) || type.equals(522));
    }

    @Override
    public AppSecret getAppSecret() {
        List<VideoPlatformEntity> list = getArtemisPlatform();
        if (list != null && list.size() > 0) {
            VideoPlatformEntity platformEntity = list.get(0);
            ArtemisConfig.appKey = platformEntity.getUsername();
            ArtemisConfig.appSecret = platformEntity.getPasswd();

            String pathKey = "https://";

            String serviceUrl = platformEntity.getSyncServiceUrl();
            int index = serviceUrl.indexOf("//");
            if (index > 0 && index < 7) {
                ArtemisConfig.host = serviceUrl.substring(index + 2);
                pathKey = serviceUrl.substring(0, index + 2);
            } else {
                ArtemisConfig.host = platformEntity.getIp() + ":" + platformEntity.getPort();
                pathKey = "https://";
            }
            Map<String, String> path = new HashMap<>();
            path.put(pathKey, ArtemisPath.security_app_secret + "/" + platformEntity.getUsername());
            String responseBody = ArtemisHttpUtil.doGetArtemis(path, null, null, contentType);
            logger.debug("getAppSecret response: {}", responseBody);

            ResponseData response = JsonUtil.INSTANCE.readValue(responseBody, ResponseData.class);
            if (response.getCode().equals("0")) {
                AppSecret appSecret = JsonUtil.INSTANCE.treeToValue(response.getData(), AppSecret.class);
                appSecret.setAppKey(platformEntity.getUsername());
                appSecret.setServerIp(platformEntity.getIp());
                appSecret.setServerPort(platformEntity.getPort());
                return appSecret;
            } else {
                logger.error("getAppSecret response: {}", responseBody);
                return null;
            }
        }
        return null;
    }

    @Override
    public List<RegionInfo> getAllRegions() {
        List<RegionInfo> list = new ArrayList<>();
        String pathKey = initArtemisConfig();
        if (pathKey != null) {
            Map<String, String> path = new HashMap<>();
            path.put(pathKey, ArtemisPath.regions);
            int pageNo = 1;
            int pageSize = defaultPageSize;
            DataRegion dataRegion = getRegionPage(path, pageNo, pageSize);
            if (dataRegion != null && dataRegion.getList().size() > 0) {
                list.addAll(dataRegion.getList());
                while (dataRegion.getTotal() > dataRegion.getPageNo() * dataRegion.getPageSize()) {
                    pageNo++;
                    dataRegion = getRegionPage(path, pageNo, pageSize);
                    if (dataRegion != null && dataRegion.getList().size() > 0) {
                        list.addAll(dataRegion.getList());
                    } else {
                        break;
                    }
                }
            }
        }
        logger.info("getAllRegions size: {}", list.size());
        return list;
    }

    private DataRegion getRegionPage(Map<String, String> path, int pageNo, int pageSize) {
        RegionsRequest request = new RegionsRequest();
        request.setPageNo(pageNo);
        request.setPageSize(pageSize);
        request.setTreeCode("0");
        String body = JsonUtil.INSTANCE.writeValueAsString(request);
        logger.debug("getRegionPage request: {}", body);
        String responseBody = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null, contentType);
        logger.debug("getRegionPage response: {}", responseBody);
        ResponseData response = JsonUtil.INSTANCE.readValue(responseBody, ResponseData.class);
        if (response.getCode().equals("0")) {
            DataRegion dataRegion = JsonUtil.INSTANCE.treeToValue(response.getData(), DataRegion.class);
            return dataRegion;
        } else {
            logger.error("getRegionPage response: {}", responseBody);
            return null;
        }
    }

    @Override
    public List<RegionInfo> getSubRegions(String regionIndexCode) {
        List<RegionInfo> list = new ArrayList<>();
        String pathKey = initArtemisConfig();
        if (pathKey != null) {
            Map<String, String> path = new HashMap<>();
            path.put(pathKey, ArtemisPath.regions_subRegions);

            SubRegionsRequest request = new SubRegionsRequest();
            request.setTreeCode("0");
            request.setParentIndexCode(regionIndexCode);
            String body = JsonUtil.INSTANCE.writeValueAsString(request);
            logger.debug("getSubRegions request: {}", body);
            String responseBody = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null, contentType);
            logger.debug("getSubRegions response: {}", responseBody);
            ResponseData response = JsonUtil.INSTANCE.readValue(responseBody, ResponseData.class);
            if (response.getCode().equals("0")) {
                DataRegion dataRegion = JsonUtil.INSTANCE.treeToValue(response.getData(), DataRegion.class);
                if (dataRegion != null && dataRegion.getTotal() > 0) {
                    list.addAll(dataRegion.getList());
                }
            } else {
                logger.error("getRegionPage response: {}", responseBody);
            }
        }
        logger.info("getSubRegions size: {}", list.size());
        return list;
    }

    @Override
    public List<CameraInfo> getAllCameras() {
        List<CameraInfo> list = new ArrayList<>();
        String pathKey = initArtemisConfig();
        if (pathKey != null) {
            Map<String, String> path = new HashMap<>();
            path.put(pathKey, ArtemisPath.cameras);
            int pageNo = 1;
            int pageSize = defaultPageSize;
            DataCamera dataCamera = getCameraPage(path, pageNo, pageSize, null);
            if (dataCamera != null && dataCamera.getList().size() > 0) {
                list.addAll(dataCamera.getList());
                while (dataCamera.getTotal() > dataCamera.getPageNo() * dataCamera.getPageSize()) {
                    pageNo++;
                    dataCamera = getCameraPage(path, pageNo, pageSize, null);
                    if (dataCamera != null && dataCamera.getList().size() > 0) {
                        list.addAll(dataCamera.getList());
                    } else {
                        break;
                    }
                }
            }
        }
        logger.info("getAllCameras size: {}", list.size());
        return list;
    }

    private DataCamera getCameraPage(Map<String, String> path, int pageNo, int pageSize, String regionIndexCode) {
        CamerasRequest request = new CamerasRequest();
        request.setPageNo(pageNo);
        request.setPageSize(pageSize);
        request.setRegionIndexCode(regionIndexCode);
        request.setTreeCode("0");
        String body = JsonUtil.INSTANCE.writeValueAsString(request);
        logger.debug("getCameraPage request: {}", body);
        String responseBody = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null, contentType);
        logger.debug("getCameraPage response: {}", responseBody);
        ResponseData response = JsonUtil.INSTANCE.readValue(responseBody, ResponseData.class);
        if (response.getCode().equals("0")) {
            DataCamera dataCamera = JsonUtil.INSTANCE.treeToValue(response.getData(), DataCamera.class);
            return dataCamera;
        } else {
            logger.error("getCameraPage response: {}", responseBody);
            return null;
        }
    }

    @Override
    public List<CameraInfo> getSubCameras(String regionIndexCode) {
        List<CameraInfo> list = new ArrayList<>();
        String pathKey = initArtemisConfig();
        if (pathKey != null) {
            Map<String, String> path = new HashMap<>();
            path.put(pathKey, ArtemisPath.regions_cameras);
            int pageNo = 1;
            int pageSize = defaultPageSize;
            DataCamera dataCamera = getCameraPage(path, pageNo, pageSize, regionIndexCode);
            if (dataCamera != null && dataCamera.getList().size() > 0) {
                list.addAll(dataCamera.getList());
                while (dataCamera.getTotal() > dataCamera.getPageNo() * dataCamera.getPageSize()) {
                    pageNo++;
                    dataCamera = getCameraPage(path, pageNo, pageSize, regionIndexCode);
                    if (dataCamera != null && dataCamera.getList().size() > 0) {
                        list.addAll(dataCamera.getList());
                    } else {
                        break;
                    }
                }
            }
        }
        logger.info("getSubCameras size: {}", list.size());
        return list;
    }

    @Override
    public String getPreviewURL(String cameraIndexCode, String protocol, Integer streamType, Integer transmode) {
        String pathKey = initArtemisConfig();
        if (pathKey != null) {
            Map<String, String> path = new HashMap<>();
            path.put(pathKey, ArtemisPath.cameras_previewURLs);

            PreviewURLsRequest request = new PreviewURLsRequest();
            request.setCameraIndexCode(cameraIndexCode);
            request.setProtocol(protocol);
            request.setStreamType(streamType != null ? streamType : 0);
            request.setTransmode(transmode != null ? transmode : 0);
            request.setExpand("transcode=0&streamform=rtp");
            String body = JsonUtil.INSTANCE.writeValueAsString(request);
            logger.debug("getPreviewURL request: {}", body);
            String responseBody = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null, contentType);
            logger.debug("getPreviewURL response: {}", responseBody);
            if (!StringUtils.isEmpty(responseBody)) {
                ResponseData response = JsonUtil.INSTANCE.readValue(responseBody, ResponseData.class);
                if (response.getCode().equals("0")) {
                    DataUrl dataUrl = JsonUtil.INSTANCE.treeToValue(response.getData(), DataUrl.class);
                    return dataUrl.getUrl();
                } else {
                    logger.error("getPreviewURL response: {}", responseBody);
                    return "";
                }
            } else {
                return "";
            }
        }
        return "";
    }

    @Override
    public String getPlaybackURL(String cameraIndexCode, String protocol, String beginTime, String endTime, Integer recordLocation) {
        String pathKey = initArtemisConfig();
        if (pathKey != null) {
            Map<String, String> path = new HashMap<>();
            path.put(pathKey, ArtemisPath.cameras_playbackURLs);

            PlaybackURLsRequest request = new PlaybackURLsRequest();
            request.setCameraIndexCode(cameraIndexCode);
            request.setProtocol(protocol);
            request.setBeginTime(beginTime);
            request.setEndTime(endTime);
            request.setExpand("transcode=0&streamform=rtp");
            request.setNeedReturnClipInfo(false);
            request.setUuid("");
            request.setRecordLocation(recordLocation != null ? recordLocation.toString() : "0");
            String body = JsonUtil.INSTANCE.writeValueAsString(request);
            logger.debug("getPlaybackURL request: {}", body);
            String responseBody = ArtemisHttpUtil.doPostStringArtemis(path, body, null, "application/json, text/plain, */*", contentType);
            logger.debug("getPlaybackURL response: {}", responseBody);
            if (!StringUtils.isEmpty(responseBody)) {
                ResponseData response = JsonUtil.INSTANCE.readValue(responseBody, ResponseData.class);
                if (response.getCode().equals("0")) {
                    DataUrl dataUrl = JsonUtil.INSTANCE.treeToValue(response.getData(), DataUrl.class);
                    return dataUrl.getUrl();
                } else {
                    logger.error("getPlaybackURL response: {}", responseBody);
                    return "";
                }
            } else {
                return "";
            }
        }
        return "";
    }

    @Override
    public String getPlaybackURL2(String cameraIndexCode, String protocol, String beginTime, String endTime, Integer recordLocation) {
        String playbackurl = "http://192.168.21.2:8080/playbackurl/getUrlIp";

        ClientConfig clientConfig = new ClientConfig();
        clientConfig.property(ClientProperties.CONNECT_TIMEOUT, 3000);
        clientConfig.property(ClientProperties.READ_TIMEOUT, 3000);
        WebTarget webTarget = ClientBuilder.newClient(clientConfig).target(playbackurl);

        PlaybackURLsRequest2 request = new PlaybackURLsRequest2();
        request.setIndexCode(cameraIndexCode);
        request.setStartTime(beginTime);
        request.setEndTime(endTime);
        request.setRecordStyle(0);
        String body = JsonUtil.INSTANCE.writeValueAsString(request);

        logger.debug("getPlaybackURL request: {}", body);
        Response response = webTarget.request("application/json, text/plain, */*")
                .post(Entity.entity(body, MediaType.APPLICATION_JSON));
        ResponseData2 responseData = response.readEntity(ResponseData2.class);
        logger.debug("getPlaybackURL response: {}", responseData);

        if (responseData.getCode().equals("0")) {
            List<DataPlaybackURL> playbackURLs = responseData.getData();
            if (playbackURLs != null && playbackURLs.size() > 0) {
                String url = playbackURLs.get(0).getPlayBackUrl();
                return getEncodeUrl(url);
            }
        }
        return "";
    }

    private String getEncodeUrl(String url) {
        try {
            return URLEncoder.encode(url, "UTF-8");
        } catch (UnsupportedEncodingException ex) {
            return url;
        }
    }

}
